#include <reg52.h>
#include <math.h>
#define uchar unsigned char
#define uint unsigned int

#define TX_ADR_WIDTH 5   // 5字节宽度的发送/接收地址
#define TX_PLOAD_WIDTH 4 // 数据通道有效数据宽度

uchar code TX_ADDRESS[TX_ADR_WIDTH] = {0x34, 0x43, 0x10, 0x10, 0x01}; // 定义一个静态发送地址
uchar RX_BUF[TX_PLOAD_WIDTH];
uchar TX_BUF[TX_PLOAD_WIDTH];

uchar flag;
uchar DATA = 0x01;
uchar bdata sta;
sbit RX_DR = sta ^ 6;
sbit TX_DS = sta ^ 5;
sbit MAX_RT = sta ^ 4;
/**************************************************
 * 自定义端口
 * 
/**************************************************/
//nrf24l01
sbit CE = P1 ^ 0;
sbit SCK = P1 ^ 1;
sbit MISO = P1 ^ 2;
sbit CSN = P1 ^ 3;
sbit MOSI = P1 ^ 4;
sbit IRQ = P1 ^ 5;
//adc0809
sbit OE = P3 ^ 4;
sbit EOC = P3 ^ 5;
sbit ST = P3 ^ 6;
sbit CLK = P3 ^ 7;

/**************************************************
 * 自定义值
 * 
/**************************************************/
// 数码管显示
uchar sz[] = {
    0x3F, //"0"
    0x06, //"1"
    0x5B, //"2"
    0x4F, //"3"
    0x66, //"4"
    0x6D, //"5"
    0x7D, //"6"
    0x07, //"7"
    0x7F, //"8"
    0x6F, //"9"
    0x77, //"A"
    0x7C, //"B"
    0x39, //"C"
    0x5E, //"D"
    0x79, //"E"
    0x71, //"F"
    0x76, //"H"
    0x38, //"L"
    0x37, //"n"
    0x3E, //"u"
    0x73, //"P"
    0x5C, //"o"
    0x40, //"-"
    0x00  //清屏
};
// 数码管值
uchar weitable[] = {
    0x8f, 0x4f, 0x2f, 0x1f};
/**************************************************
函数：DelayMS()
描述：
    延迟x毫秒
/**************************************************/
void DelayMS(uint ms)
{
    uchar i;
    while (ms--)
        for (i = 0; i < 112; i++)
            ;
}

/**************************************************
 * 数码管定义
 * 
/**************************************************/
void display1(uchar wei, uchar shu)
{
    wei--;
    P2 |= 0xf0;
    P0 = sz[shu];
    P2 = P2 & weitable[wei];
    DelayMS(5);
}
void display(uchar a, uchar b, uchar c, uchar d)
{
    display1(4, a);
    display1(3, b);
    display1(2, c);
    display1(1, d);
}
/**************************************************
 * adc0809定义
 * 
/**************************************************/
void adcInit(void)
{
    TMOD = 0x02;
    TH0 = 0x14;
    TL0 = 0x00;
    // TH0 = 246; //定时器初值高8位
    // TL0 = 246; //定时器初值低8位
    EA = 1;
    ET0 = 1; //开定时器中断
    TR0 = 1;
}
// char Display_Result(uchar m)
// {
//     uchar ch[4];
//     uint d = m;
//     /**********根据当前输入量m大小 ，在【0-255】所占比例，转换为当前数字量 **********/
//     float k = d * 1.00;
//     k = (k / 256 * 5 * 1000); //1000代表当前所设定电阻的值。256代表整体【0-255】的长度
//     d = k;
//     /*****P0口分别显示个、十、百、千等位的大小（段码），P2显示的位置（位码）***********/
//     P3 = 0x7f; //个 01111111
//     P0 = sz[d % 10];
//     DelayMS(1);
//     P3 = 0xbf; //十 10111111
//     P0 = sz[d / 10 % 10];
//     DelayMS(1);
//     P3 = 0xdf; //百 11011111
//     P0 = sz[d / 100 % 10];
//     DelayMS(1);
//     P3 = 0xef; //千 11101111
//     P0 = sz[d / 1000] | 0x80;
//     DelayMS(1);
//     ch[3] = d % 10;
//     ch[2] = d / 10 % 10;
//     ch[1] = d / 100 % 10;
//     ch[0] = d / 1000;
//     return ch;
// }
uchar adcvalue(uchar p)
{
    uint d = p;
    /**********根据当前输入量m大小 ，在【0-255】所占比例，转换为当前数字量 **********/
    float k = d * 1.00;
    k = (k / 256 * 5 * 1000); //1000代表当前所设定电阻的值。256代表整体【0-255】的长度
    d = k;
    TX_BUF[3] = d % 10;
    TX_BUF[2] = d / 10 % 10;
    TX_BUF[1] = d / 100 % 10;
    TX_BUF[0] = d / 1000;
}
/**************************************************
 * 键盘定义
 * 
/**************************************************/
// uchar key = 0xff; //键值

uint keyscan4x4()
{
    uchar temp;
    uint keyvalue = 0xff;
    // 第一行扫描
    P3 = 0xfe; //1111 1110
    temp = P3;
    temp = temp & 0xf0; //1111 0000 与 后屏蔽后四位
    if (temp != 0xf0)
    {
        DelayMS(10);
        temp = P3;
        temp = temp & 0xf0;
        if (temp != 0xf0)
        {
            temp = P3;
            switch (temp)
            {
            case 0xee: //1110 1110
                keyvalue = 1;
                break;
            case 0xde: //1101 1110
                keyvalue = 2;
                break;
            case 0xbe:
                keyvalue = 3;
                break;
            case 0x7e:
                keyvalue = 10;
                break;
            }
        }
        while (temp != 0xf0)
        {
            temp = P3;
            temp = temp & 0xf0;
        }
        P0 = sz[keyvalue];
    }
    // 第二行扫描
    P3 = 0xfd; //1111 1101
    temp = P3;
    temp = temp & 0xf0; //1111 0000 与 后屏蔽后四位
    if (temp != 0xf0)
    {
        DelayMS(10);
        temp = P3;
        temp = temp & 0xf0;
        if (temp != 0xf0)
        {
            temp = P3;
            switch (temp)
            {
            case 0xed: //1110 1101
                keyvalue = 4;
                break;
            case 0xdd: //1101 1101
                keyvalue = 5;
                break;
            case 0xbd:
                keyvalue = 6;
                break;
            case 0x7d:
                keyvalue = 11;
                break;
            }
        }
        while (temp != 0xf0)
        {
            temp = P3;
            temp = temp & 0xf0;
        }
        P0 = sz[keyvalue];
    }
    // 第三行扫描
    P3 = 0xfb; //1111 1011
    temp = P3;
    temp = temp & 0xf0; //1111 0000 与 后屏蔽后四位
    if (temp != 0xf0)
    {
        DelayMS(10);
        temp = P3;
        temp = temp & 0xf0;
        if (temp != 0xf0)
        {
            temp = P3;
            switch (temp)
            {
            case 0xed: //1110 1011
                keyvalue = 7;
                break;
            case 0xdd: //1101 1011
                keyvalue = 8;
                break;
            case 0xbd:
                keyvalue = 9;
                break;
            case 0x7d:
                keyvalue = 12;
                break;
            }
        }
        while (temp != 0xf0)
        {
            temp = P3;
            temp = temp & 0xf0;
        }
        P0 = sz[keyvalue];
    }
    // 第四行扫描
    P3 = 0xf7; //1111 0111
    temp = P3;
    temp = temp & 0xf0; //1111 0000 与 后屏蔽后四位
    if (temp != 0xf0)
    {
        DelayMS(10);
        temp = P3;
        temp = temp & 0xf0;
        if (temp != 0xf0)
        {
            temp = P3;
            switch (temp)
            {
            case 0xed: //1110 0111
                keyvalue = 0;
                break;
            case 0xdd: //1101 0111
                keyvalue = 0;
                break;
            case 0xbd:
                keyvalue = 0;
                break;
            case 0x7d:
                keyvalue = 13;
                break;
            }
        }
        while (temp != 0xf0)
        {
            temp = P3;
            temp = temp & 0xf0;
        }
        P0 = sz[keyvalue];
    }
    return (keyvalue);
}
/**************************************************
nrf24l01设定
描述:
    不可随意更改
/**************************************************/
// SPI(nRF24L01) commands
#define READ_REG 0x00    // Define read command to register
#define WRITE_REG 0x20   // Define write command to register
#define RD_RX_PLOAD 0x61 // Define RX payload register address
#define WR_TX_PLOAD 0xA0 // Define TX payload register address
#define FLUSH_TX 0xE1    // Define flush TX register command
#define FLUSH_RX 0xE2    // Define flush RX register command
#define REUSE_TX_PL 0xE3 // Define reuse TX payload register command
#define NOP 0xFF         // Define No Operation, might be used to read status register

// SPI(nRF24L01) registers(addresses)
#define CONFIG 0x00      // 'Config' register address
#define EN_AA 0x01       // 'Enable Auto Acknowledgment' register address
#define EN_RXADDR 0x02   // 'Enabled RX addresses' register address
#define SETUP_AW 0x03    // 'Setup address width' register address
#define SETUP_RETR 0x04  // 'Setup Auto. Retrans' register address
#define RF_CH 0x05       // 'RF channel' register address
#define RF_SETUP 0x06    // 'RF setup' register address
#define STATUS 0x07      // 'Status' register address
#define OBSERVE_TX 0x08  // 'Observe TX' register address
#define CD 0x09          // 'Carrier Detect' register address
#define RX_ADDR_P0 0x0A  // 'RX address pipe0' register address
#define RX_ADDR_P1 0x0B  // 'RX address pipe1' register address
#define RX_ADDR_P2 0x0C  // 'RX address pipe2' register address
#define RX_ADDR_P3 0x0D  // 'RX address pipe3' register address
#define RX_ADDR_P4 0x0E  // 'RX address pipe4' register address
#define RX_ADDR_P5 0x0F  // 'RX address pipe5' register address
#define TX_ADDR 0x10     // 'TX address' register address
#define RX_PW_P0 0x11    // 'RX payload width, pipe0' register address
#define RX_PW_P1 0x12    // 'RX payload width, pipe1' register address
#define RX_PW_P2 0x13    // 'RX payload width, pipe2' register address
#define RX_PW_P3 0x14    // 'RX payload width, pipe3' register address
#define RX_PW_P4 0x15    // 'RX payload width, pipe4' register address
#define RX_PW_P5 0x16    // 'RX payload width, pipe5' register address
#define FIFO_STATUS 0x17 // 'FIFO Status Register' register address

/**************************************************
函数: init_io()
描述:
    初始化IO
/**************************************************/
void init_io(void)
{
    CE = 0;  // 待机
    CSN = 1; // SPI禁止
    SCK = 0; // SPI时钟置低
    IRQ = 1; // 中断复位
    // LED = 1; // 关闭指示灯
}
/**************************************************/

/**************************************************
函数：SPI_RW()
描述：
    根据SPI协议，写一字节数据到nRF24L01，同时从nRF24L01
    读出一字节
/**************************************************/
uchar SPI_RW(uchar byte)
{
    uchar i;
    for (i = 0; i < 8; i++) // 循环8次
    {
        MOSI = (byte & 0x80); // byte最高位输出到MOSI
        byte <<= 1;           // 低一位移位到最高位
        SCK = 1;              // 拉高SCK，nRF24L01从MOSI读入1位数据，同时从MISO输出1位数据
        byte |= MISO;         // 读MISO到byte最低位
        SCK = 0;              // SCK置低
    }
    return (byte); // 返回读出的一字节
}
/**************************************************/

/**************************************************
函数：SPI_RW_Reg()
描述：
    写数据value到reg寄存器
/**************************************************/
uchar SPI_RW_Reg(uchar reg, uchar value)
{
    uchar status;
    CSN = 0;              // CSN置低，开始传输数据
    status = SPI_RW(reg); // 选择寄存器，同时返回状态字
    SPI_RW(value);        // 然后写数据到该寄存器
    CSN = 1;              // CSN拉高，结束数据传输
    return (status);      // 返回状态寄存器
}
/**************************************************/

/**************************************************
函数：SPI_Read()
描述：
    从reg寄存器读一字节
/**************************************************/
uchar SPI_Read(uchar reg)
{
    uchar reg_val;
    CSN = 0;             // CSN置低，开始传输数据
    SPI_RW(reg);         // 选择寄存器
    reg_val = SPI_RW(0); // 然后从该寄存器读数据
    CSN = 1;             // CSN拉高，结束数据传输
    return (reg_val);    // 返回寄存器数据
}
/**************************************************/

/**************************************************
函数：SPI_Read_Buf()
描述：
    从reg寄存器读出bytes个字节，通常用来读取接收通道
    数据或接收/发送地址
/**************************************************/
uchar SPI_Read_Buf(uchar reg, uchar *pBuf, uchar bytes)
{
    uchar status, i;
    CSN = 0;              // CSN置低，开始传输数据
    status = SPI_RW(reg); // 选择寄存器，同时返回状态字
    for (i = 0; i < bytes; i++)
        pBuf[i] = SPI_RW(0); // 逐个字节从nRF24L01读出
    CSN = 1;                 // CSN拉高，结束数据传输
    return (status);         // 返回状态寄存器
}
/**************************************************/

/**************************************************
函数：SPI_Write_Buf()
描述：
    把pBuf缓存中的数据写入到nRF24L01，通常用来写入发
    射通道数据或接收/发送地址
/**************************************************/
uchar SPI_Write_Buf(uchar reg, uchar *pBuf, uchar bytes)
{
    uchar status, i;
    CSN = 0;              // CSN置低，开始传输数据
    status = SPI_RW(reg); // 选择寄存器，同时返回状态字
    for (i = 0; i < bytes; i++)
        SPI_RW(pBuf[i]); // 逐个字节写入nRF24L01
    CSN = 1;             // CSN拉高，结束数据传输
    return (status);     // 返回状态寄存器
}
/**************************************************/

/**************************************************
函数：RX_Mode()
描述：
    这个函数设置nRF24L01为接收模式，等待接收发送设备的数据包
/**************************************************/
void RX_Mode(void)
{
    CE = 0;
    SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // 接收设备接收通道0使用和发送设备相同的发送地址
    SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);                             // 使能接收通道0自动应答
    SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);                         // 使能接收通道0
    SPI_RW_Reg(WRITE_REG + RF_CH, 40);                               // 选择射频通道0x40
    SPI_RW_Reg(WRITE_REG + RX_PW_P0, TX_PLOAD_WIDTH);                // 接收通道0选择和发送通道相同有效数据宽度
    SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07);                          // 数据传输率1Mbps，发射功率0dBm，低噪声放大器增益
    SPI_RW_Reg(WRITE_REG + CONFIG, 0x0f);                            // CRC使能，16位CRC校验，上电，接收模式
    DelayMS(150);
    CE = 1; // 拉高CE启动接收设备
}
/**************************************************/

/**************************************************
函数：TX_Mode()
描述：
    这个函数设置nRF24L01为发送模式，（CE=1持续至少10us），
    130us后启动发射，数据发送结束后，发送模块自动转入接收
    模式等待应答信号。
/**************************************************/
void TX_Mode(uchar *BUF)
{
    CE = 0;
    SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH);    // 写入发送地址
    SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // 为了应答接收设备，接收通道0地址和发送地址相同
    SPI_Write_Buf(WR_TX_PLOAD, BUF, TX_PLOAD_WIDTH);                 // 写数据包到TX FIFO
    SPI_RW_Reg(WRITE_REG + EN_AA, 0x01);                             // 使能接收通道0自动应答
    SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01);                         // 使能接收通道0
    SPI_RW_Reg(WRITE_REG + SETUP_RETR, 0x0a);                        // 自动重发延时等待250us+86us，自动重发10次
    SPI_RW_Reg(WRITE_REG + RF_CH, 40);                               // 选择射频通道0x40
    SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x07);                          // 数据传输率1Mbps，发射功率0dBm，低噪声放大器增益
    SPI_RW_Reg(WRITE_REG + CONFIG, 0x0e);                            // CRC使能，16位CRC校验，上电
    DelayMS(150);
    CE = 1;
}
/**************************************************/

/**************************************************
函数：Check_ACK()
描述：
    检查接收设备有无接收到数据包，设定没有收到应答信
    号是否重发
/**************************************************/
uchar Check_ACK(bit clear)
{
    DelayMS(200);
    while (IRQ)
        ;
    sta = SPI_RW(NOP); // 返回状态寄存器
    if (TX_DS)
    {
        // blink(3);
        //fm = 1;
    }
    //blink(5);
    if (MAX_RT)
        if (clear) // 是否清除TX FIFO，没有清除在复位MAX_RT中断标志后重发
            SPI_RW(FLUSH_TX);
    SPI_RW_Reg(WRITE_REG + STATUS, sta); // 清除TX_DS或MAX_RT中断标志
    IRQ = 1;
    if (TX_DS)
        return (0x00);
    else
        return (0xff);
}
/**************************************************/

/**************************************************
函数：main()
描述：
    主函数
/**************************************************/
void main(void)
{
    uint i = 0, j;
    uchar addr;
    // uint key;
    // uchar value[4];
    addr = 0x1F;
    for (j = 0; j < TX_PLOAD_WIDTH - 1; j++)
        TX_BUF[j] = '\0';
    init_io(); // 初始化nrf24L01
    adcInit(); //初始化adc
    while (1)
    {

        ST = 0;
        ST = 1;
        ST = 0;
        while (EOC == 0)
            ;
        OE = 1;
        adcvalue(P2);
        TX_Mode(TX_BUF); // 把nRF24L01设置为发送模式并发送数据
        Check_ACK(0);    // 等待发送完毕，清除TX FIFO
        DelayMS(10);
        OE = 0;
        // TX_BUF[0] = 1;

        // // *TX_BUF = P2;
        // // *value = adcvalue(P2);
        // // DelayMS(10);

        // TX_BUF[0] = value[0];

        // key = keyscan4x4();
        // if ((key != 0xff) && (key != 10))
        // {
        //     for (j = 0; j < TX_PLOAD_WIDTH - 1; j++)
        //         TX_BUF[j] = TX_BUF[j + 1];
        //     TX_BUF[TX_PLOAD_WIDTH - 1] = key; //数据送到缓存
        // }
        // if (key == 10)
        // {
        //     TX_Mode(TX_BUF); // 把nRF24L01设置为发送模式并发送数据
        //     Check_ACK(0);    // 等待发送完毕，清除TX FIFO
        //     DelayMS(1);
        //     key = 0xff;
        //     for (j = 0; j < TX_PLOAD_WIDTH - 1; j++)
        //         TX_BUF[j] = '\0';
        // }
        // while (i < TX_PLOAD_WIDTH)
        // {
        //     P0 = sz[TX_BUF[i]];
        //     P2 = addr;
        //     addr += pow(2, i) * 0x10;
        //     i++;
        // }
        // i = 0;
        // addr = 0x1F;
    }
}
void Timer0_INT() interrupt 1
{
    CLK = ~CLK;
}